/* Show the capability of a USB device. Used in `listmouse' and `listkeyboard'. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>

#include <sys/ioctl.h>
#include <sys/mman.h>
#include <termios.h>
#include <sys/vt.h>
#include <sys/time.h>
#include <sys/types.h>

#include <linux/fb.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include <linux/input.h>

/* this macro is used to tell if "bit" is set in "array"
 * it selects a byte from the array, and does a boolean AND 
 * operation with a byte that only has the relevant bit set. 
 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
 */
#define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))

int main(int argc, char *argv[])
{
	if(argc<2){
		fprintf(stderr, "Usage: capable device_name\n");
		exit(1);
	}
	
	char *device_name = argv[1];

	/* Initialize the mouse */
	int fd = open(device_name, O_RDWR);
	if (fd < 0) {
		fprintf(stderr, "Can't initialize device\n");
		return false;
	}
	
	// Check if the opened device is a mouse
	uint8_t evtype_bitmask[EV_MAX/8 + 1];
	if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype_bitmask)), evtype_bitmask) >= 0) {
		printf("%s Support: \n", device_name);
		if(test_bit(EV_SYN,evtype_bitmask)) printf(" EV_SYN \n");
		if(test_bit(EV_KEY,evtype_bitmask)) printf(" EV_KEY absolute binary results, such as keys and buttons.\n");
		if(test_bit(EV_REL,evtype_bitmask)) printf(" EV_REL relative results, such as the axes on a mouse.\n");
		if(test_bit(EV_ABS,evtype_bitmask)) printf(" EV_ABS absolute integer results, such as the axes on a joystick or for a tablet.\n");
		if(test_bit(EV_MSC,evtype_bitmask)) printf(" EV_MSC miscellaneous uses that didn't fit anywhere else.\n");
		if(test_bit(EV_LED,evtype_bitmask)) printf(" EV_LED LEDs and similar indications.\n");
		if(test_bit(EV_SND,evtype_bitmask)) printf(" EV_SND sound output, such as buzzers.\n");
		if(test_bit(EV_REP,evtype_bitmask)) printf(" EV_REP enables autorepeat of keys in the input core.\n");
		if(test_bit(EV_FF,evtype_bitmask)) printf(" EV_FF sends force-feedback effects to a device.\n");
		if(test_bit(EV_FF_STATUS,evtype_bitmask)) printf(" EV_FF_STATUS device reporting of force-feedback effects back to the host.\n");
		if(test_bit(EV_PWR,evtype_bitmask)) printf(" EV_PWR power management events.\n");
		printf("\n");
	} else {
		fprintf(stderr, "Can't get capable info\n");
	}

	close(fd);

	return 0;
}
